import {
  Component,
  ViewEncapsulation,
  ChangeDetectionStrategy,
  Input,
  TemplateRef,
  ViewChild,
  ElementRef,
  Renderer2,
  Output,
  EventEmitter,
  ChangeDetectorRef,
  forwardRef,
  SimpleChanges,
  OnChanges,
  AfterViewInit,
} from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { InputNumber, InputBoolean, TypeUtils, I18NService } from '../core/api';
import { AutocompleteItem } from '../autocomplete/interface';
import { LvConfig } from '../core/config';

@Component({
  selector: 'lv-search',
  exportAs: 'lvSearch',
  templateUrl: './search.component.html',
  encapsulation: ViewEncapsulation.None,
  changeDetection: ChangeDetectionStrategy.OnPush,
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef((): typeof SearchComponent => SearchComponent),
      multi: true,
    },
  ],
  host: {
    '[class.lv-search]': 'true',
    '[class.lv-search-inner]': 'lvType == "inner"',
  },
})
export class SearchComponent implements ControlValueAccessor, OnChanges, AfterViewInit {
  // 自动完成的接口
  @Input() lvAutocomplete: boolean = false;

  @Input() lvAutocompletePanelClass: string;

  @Input() lvAutocompleteLoading: boolean = false;

  @Input() lvType: 'default' | 'inner' = 'default';

  @Input() @InputBoolean() lvFocus: boolean = false;

  @Input() @InputBoolean() lvLoading: boolean = false;

  @Input() @InputBoolean() lvDisabled: boolean = false;

  @Output() readonly lvClear = new EventEmitter<any>();

  @Output() readonly lvSearch = new EventEmitter<any>();

  @Output() readonly lvOnFocus = new EventEmitter<any>();

  @Input() lvAutocompleteLabelTemplate: TemplateRef<void>;

  @ViewChild('input', { static: false }) input: ElementRef<any>;

  @Input() lvAutocompleteData: string[] | AutocompleteItem[] = [];

  @Input() lvPlaceHolder: string = this.i18n.get('searchPlaceholder');

  @Output() lvAutocompleteInputChange: EventEmitter<any> = new EventEmitter();

  @Input() @InputNumber() lvMaxLength: number = LvConfig.searchOptions.lvMaxLength || 100;

  public value = '';

  showPlaceHolder = true;
  public typeUtils = TypeUtils;
  public assetsPrefixPath = LvConfig.assetsPrefixPath;
  constructor(
    private renderer: Renderer2,
    private _cdr: ChangeDetectorRef,
    private i18n: I18NService,
  ) {}

  keyup(): void {
    this.isShowPlaceHolder();
  }

  focus(): void {
    this.lvOnFocus.emit(this.value);
  }

  registerOnChange(fn: any): void {
    this._onChange = fn;
  }

  registerOnTouched(fn: any): void {
    this._onTouch = fn;
  }

  autocompleteInputChange(e): void {
    this.lvAutocompleteInputChange.emit(e);
  }

  isManual(): boolean {
    return Array.from(this.lvSearch.observers).length > 0;
  }

  search(): void {
    this.lvSearch.emit(this.value);
    this._cdr.markForCheck();
  }

  inputChange(value): void {
    this.value = value;
    this.isShowPlaceHolder();
    this._onChange(value);
  }

  clear(): void {
    this.input.nativeElement.value = '';
    this.inputChange('');
    this.search();
    this.lvClear.emit();
  }

  isShowPlaceHolder(): void {
    this.showPlaceHolder =
      (this.value === '' || !this.value) && this.input && this.input.nativeElement.value === '' ? true : false;
    this._cdr.markForCheck();
  }

  writeValue(value: string): void {
    this.value = value;
    this._cdr.markForCheck();
    const delay = setTimeout((): void => {
      this.isShowPlaceHolder();
      clearTimeout(delay);
    }, 0);
  }

  ngOnChanges(changes: SimpleChanges): void {
    if (changes.lvLoading) {
      if (changes.lvLoading.previousValue === true) {
        setTimeout((): void => {
          this.input.nativeElement.focus();
        }, 0);
      }
    }
  }

  ngAfterViewInit(): void {
    if (this.lvFocus) {
      const delay = setTimeout((): void => {
        this.input.nativeElement.focus();
        clearTimeout(delay);
      }, 0);
    }
    this.renderer.listen(this.input.nativeElement, 'keydown', (e): void => {
      if (e.keyCode === 13) {
        this.search();
      }
    });
  }

  private _onTouch: any = (): void => {};

  private _onChange: any = (): void => {};
}
